package com.fsserver.core.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fsserver.common.constants.PaymentConstants;
import com.fsserver.common.exception.BusinessException;
import com.fsserver.core.dto.RefundRequestDTO;
import com.fsserver.core.entity.PaymentTransaction;
import com.fsserver.core.entity.Refund;
import com.fsserver.core.mapper.RefundMapper;
import com.fsserver.core.service.PaymentService;
import com.fsserver.core.service.PaymentStrategy;
import com.fsserver.core.service.RefundService;
import com.fsserver.core.vo.RefundResponseVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 退款服务实现类
 * Refund Service Implementation
 *
 * @author fsserver
 */
@Slf4j
@Service
public class RefundServiceImpl extends ServiceImpl<RefundMapper, Refund> implements RefundService {

    @Autowired
    private PaymentService paymentService;

    @Autowired
    private Map<String, PaymentStrategy> paymentStrategyMap;

    /**
     * 创建退款
     * Create refund
     *
     * @param refundRequestDTO 退款请求DTO
     * @return 退款响应
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public RefundResponseVO createRefund(RefundRequestDTO refundRequestDTO) {
        log.info("创建退款: {}", refundRequestDTO);
        
        // 获取支付交易 - 先通过订单号查询
        PaymentTransaction paymentTransaction = null;
        
        // 如果有交易号，则通过交易号查询
        if (refundRequestDTO.getTransactionNo() != null && !refundRequestDTO.getTransactionNo().isEmpty()) {
            // 这里假设PaymentService有一个通过交易号查询的方法
            // 如果没有，需要添加该方法或使用其他方式查询
            // 暂时使用订单号查询，实际实现时需要修改
            paymentTransaction = paymentService.queryPayment(refundRequestDTO.getOrderNo(), null);
        } else {
            // 通过订单号查询
            paymentTransaction = paymentService.queryPayment(refundRequestDTO.getOrderNo(), null);
        }
        
        if (paymentTransaction == null) {
            log.error("支付交易不存在: {}", refundRequestDTO.getOrderNo());
            throw new BusinessException("支付交易不存在");
        }
        
        String paymentType = paymentTransaction.getPaymentType();
        
        // 检查交易状态
        if (!PaymentConstants.PaymentStatus.SUCCESS.equals(paymentTransaction.getStatus())) {
            log.error("支付交易状态不允许退款: {}, {}, {}", refundRequestDTO.getOrderNo(), paymentType, paymentTransaction.getStatus());
            throw new BusinessException("支付交易状态不允许退款");
        }
        
        // 检查退款金额
        if (refundRequestDTO.getAmount().compareTo(paymentTransaction.getAmount()) > 0) {
            log.error("退款金额不能大于支付金额: {}, {}", refundRequestDTO.getAmount(), paymentTransaction.getAmount());
            throw new BusinessException("退款金额不能大于支付金额");
        }
        
        // 获取支付策略
        PaymentStrategy paymentStrategy = getPaymentStrategy(paymentType);
        
        // 创建退款
        Refund refund = createRefundEntity(paymentTransaction, refundRequestDTO);
        
        // 调用支付策略创建退款
        RefundResponseVO refundResponseVO = paymentStrategy.createRefund(refundRequestDTO, refund);
        
        log.info("退款创建成功: {}, {}", refundRequestDTO.getOrderNo(), refund.getRefundNo());
        return refundResponseVO;
    }

    /**
     * 查询退款
     * Query refund
     *
     * @param refundNo 退款号
     * @return 退款
     */
    @Override
    public Refund queryRefund(String refundNo) {
        log.info("查询退款: {}", refundNo);
        
        // 获取退款
        Refund refund = getOne(new LambdaQueryWrapper<Refund>()
                .eq(Refund::getRefundNo, refundNo));
        
        if (refund == null) {
            log.error("退款不存在: {}", refundNo);
            throw new BusinessException("退款不存在");
        }
        
        // 获取支付策略
        PaymentStrategy paymentStrategy = getPaymentStrategy(refund.getPaymentType());
        
        // 调用支付策略查询退款
        Refund updatedRefund = paymentStrategy.queryRefund(refundNo);
        
        // 更新退款
        if (updatedRefund != null && !refund.getStatus().equals(updatedRefund.getStatus())) {
            // 更新退款状态
            updateById(updatedRefund);
            return updatedRefund;
        }
        
        return refund;
    }

    /**
     * 根据订单号查询退款列表
     * List refunds by order number
     *
     * @param orderNo 订单号
     * @return 退款列表
     */
    @Override
    public List<Refund> listRefundsByOrderNo(String orderNo) {
        log.info("根据订单号查询退款列表: {}", orderNo);
        
        return list(new LambdaQueryWrapper<Refund>()
                .eq(Refund::getOrderNo, orderNo)
                .orderByDesc(Refund::getCreateTime));
    }

    /**
     * 根据交易号查询退款列表
     * List refunds by transaction number
     *
     * @param transactionNo 交易号
     * @return 退款列表
     */
    @Override
    public List<Refund> listRefundsByTransactionNo(String transactionNo) {
        log.info("根据交易号查询退款列表: {}", transactionNo);
        
        return list(new LambdaQueryWrapper<Refund>()
                .eq(Refund::getTransactionNo, transactionNo)
                .orderByDesc(Refund::getCreateTime));
    }

    /**
     * 处理退款通知
     * Handle refund notification
     *
     * @param paymentType 支付类型
     * @param params      通知参数
     * @return 是否成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean handleRefundNotification(String paymentType, Map<String, String> params) {
        log.info("处理退款通知: {}, {}", paymentType, params);
        
        // 获取支付策略
        PaymentStrategy paymentStrategy = getPaymentStrategy(paymentType);
        
        // 调用支付策略处理退款通知
        Refund refund = paymentStrategy.handleRefundNotification(params);
        
        if (refund != null) {
            // 获取原退款
            Refund originalRefund = getOne(new LambdaQueryWrapper<Refund>()
                    .eq(Refund::getRefundNo, refund.getRefundNo()));
            
            if (originalRefund != null) {
                // 更新退款
                refund.setId(originalRefund.getId());
                updateById(refund);
                
                log.info("退款通知处理成功: {}, {}", paymentType, refund.getRefundNo());
                return true;
            }
        }
        
        log.error("退款通知处理失败: {}", paymentType);
        return false;
    }
    
    /**
     * 创建退款实体
     * Create refund entity
     *
     * @param paymentTransaction 支付交易
     * @param refundRequestDTO   退款请求DTO
     * @return 退款
     */
    private Refund createRefundEntity(PaymentTransaction paymentTransaction, RefundRequestDTO refundRequestDTO) {
        // 创建退款
        Refund refund = new Refund();
        refund.setRefundNo(generateRefundNo());
        refund.setOrderNo(paymentTransaction.getOrderNo());
        refund.setTransactionNo(paymentTransaction.getTransactionNo());
        refund.setPaymentType(paymentTransaction.getPaymentType());
        refund.setAmount(refundRequestDTO.getAmount());
        refund.setCurrency(paymentTransaction.getCurrency());
        refund.setStatus(PaymentConstants.RefundStatus.INIT);
        refund.setReason(refundRequestDTO.getReason());
        refund.setUserId(paymentTransaction.getUserId());
        refund.setUserName(paymentTransaction.getUserName());
        refund.setUserIp(refundRequestDTO.getUserIp());
        
        // 保存退款
        save(refund);
        
        return refund;
    }
    
    /**
     * 获取支付策略
     * Get payment strategy
     *
     * @param paymentType 支付类型
     * @return 支付策略
     */
    private PaymentStrategy getPaymentStrategy(String paymentType) {
        PaymentStrategy paymentStrategy = paymentStrategyMap.get(paymentType);
        if (paymentStrategy == null) {
            log.error("支付类型不支持: {}", paymentType);
            throw new BusinessException("支付类型不支持");
        }
        return paymentStrategy;
    }
    
    /**
     * 生成退款号
     * Generate refund number
     *
     * @return 退款号
     */
    private String generateRefundNo() {
        // 生成退款号：R + 时间戳 + 6位随机数
        return "R" + System.currentTimeMillis() + String.format("%06d", (int) (Math.random() * 1000000));
    }
} 